Facade
门面(Facade)
门面为容器中的类提供了一个静态调用接口,相比于传统的静态方法调用, 带来了更好的可测试性和扩展性,你可以为任何的非静态类库定义一个facade类。
系统已经为大部分核心类库定义了
Facade,所以你可以通过Facade来访问这些系统类,当然也可以为你的应用类库添加静态代理。
下面是一个示例,假如我们定义了一个app\common\Test类,里面有一个hello动态方法。
phpnamespace app\common;class Test{public function hello($name){return 'hello,' . $name;}}
调用hello方法的代码应该类似于:
$test = new \app\common\Test;echo $test->hello('thinkphp'); // 输出 hello,thinkphp
接下来,我们给这个类定义一个静态代理类app\facade\Test(这个类名不一定要和Test类一致,但通常为了便于管理,建议保持名称统一)。
phpnamespace app\facade;use think\Facade;class Test extends Facade{protected static function getFacadeClass(){return 'app\common\Test';}}
只要这个类库继承think\Facade,就可以使用静态方式调用动态类app\common\Test的动态方法,例如上面的代码就可以改成:
// 无需进行实例化 直接以静态方法方式调用helloecho \app\facade\Test::hello('thinkphp');
结果也会输出 hello,thinkphp。
说的直白一点,Facade功能可以让类无需实例化而直接进行静态方式调用。
如果没有通过getFacadeClass方法显式指定要静态代理的类,可以在调用的时候进行动态绑定:
phpnamespace app\facade;use think\Facade;class Test extends Facade{}use app\facade\Test;use think\Facade;Facade::bind('app\facade\Test', 'app\common\Test');echo Test::hello('thinkphp');
bind方法支持批量绑定,因此你可以在应用的公共函数文件中统一进行绑定操作,例如:
Facade::bind(['app\facade\Test' => 'app\common\Test','app\facade\Info' => 'app\common\Info',]);
核心Facade类库
系统给内置的常用类库定义了Facade类库,包括:
| (动态)类库 | Facade类 |
|---|---|
| think\App | think\facade\App |
| think\Build | think\facade\Build |
| think\Cache | think\facade\Cache |
| think\Config | think\facade\Config |
| think\Cookie | think\facade\Cookie |
| think\Debug | think\facade\Debug |
| think\Env | think\facade\Env |
| think\Hook | think\facade\Hook |
| think\Lang | think\facade\Lang |
| think\Log | think\facade\Log |
| think\Middleware | think\facade\Middleware |
| think\Request | think\facade\Request |
| think\Response | think\facade\Response |
| think\Route | think\facade\Route |
| think\Session | think\facade\Session |
| think\Url | think\facade\Url |
| think\Validate | think\facade\Validate |
| think\View | think\facade\View |
所以你无需进行实例化就可以很方便的进行方法调用,例如:
use think\facade\Cache;Cache::set('name','value');echo Cache::get('name');
think\Db类的实现本来就类似于Facade机制,所以不需要再进行静态代理就可以使用静态方法调用(确切的说Db类是没有方法的,都是调用的Query类的方法)。
在进行依赖注入的时候,请不要使用Facade类作为类型约束,而是建议使用原来的动态类,下面是错误的用法:
phpnamespace app\index\controller;use think\facade\App;class Index{public function index(App $app){}}
应当使用下面的方式:
phpnamespace app\index\controller;use think\App;class Index{public function index(App $app){}}
为了更加方便的使用系统类库,系统还给这些常用的核心类库的Facade类注册了类库别名,当进行静态调用的时候可以直接使用简化的别名进行调用。
| 别名类 | 对应Facade类 |
|---|---|
| App | think\facade\App |
| Build | think\facade\Build |
| Cache | think\facade\Cache |
| Config | think\facade\Config |
| Cookie | think\facade\Cookie |
| Db | think\Db |
| Debug | think\facade\Debug |
| Env | think\facade\Env |
| Hook | think\facade\Hook |
| Lang | think\facade\Lang |
| Log | think\facade\Log |
| Middleware | think\facade\Middleware |
| Request | think\facade\Request |
| Response | think\facade\Response |
| Route | think\facade\Route |
| Session | think\facade\Session |
| Url | think\facade\Url |
| Validate | think\facade\Validate |
| View | think\facade\View |
因此前面的代码可以改成
\Cache::set('name','value');echo \Cache::get('name');
Facade类定义了一个实例化的
instance方法,如果你的类也有定义的话将会失效。